using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.EventSystems;
using UnityEngine.UI;

[RequireComponent(typeof(ScrollRect))]
public class ScrollRectSnapElement : MonoBehaviour, IBeginDragHandler, IEndDragHandler, IEventSystemHandler
{
	protected enum SnappingStep
	{
		None,
		Drag,
		PrepareToSnapping,
		Snapping
	}

	protected SnappingStep m_Step;

	public Action<RectTransform> onSnapElementComplete;

	public Action onSnapElementObjectEnable;

	protected RectTransform m_FocusedElement;

	public int currentIndex;

	protected List<RectTransform> m_ElementList;

	protected List<Vector3> m_PositionList;

	protected ScrollRect m_ScrollRect;

	protected RectTransform m_ScrollRectTrans;

	protected RectTransform m_RectContentTrans;

	protected float m_FromHorizontalPosition;

	protected float m_ToHorizontalPosition;

	protected float m_Time;

	[SerializeField]
	protected float m_SpeedThreshold;

	[SerializeField]
	[Range(0.2f, 1f)]
	protected float m_SnapTime;

	[SerializeField]
	protected bool m_SnapAtAwake;

	[SerializeField]
	protected LevelIndexUI m_LevelIndexUI;

	private void Awake()
	{
		if (m_SnapAtAwake)
		{
			Initialize();
		}
	}

	public void Initialize()
	{
		m_ElementList = new List<RectTransform>();
		if (m_ScrollRect == null)
		{
			m_ScrollRect = GetComponent<ScrollRect>();
			m_ScrollRectTrans = (m_ScrollRect.transform as RectTransform);
			m_RectContentTrans = m_ScrollRect.content;
		}
		IEnumerator enumerator = m_RectContentTrans.GetEnumerator();
		try
		{
			while (enumerator.MoveNext())
			{
				RectTransform item = (RectTransform)enumerator.Current;
				m_ElementList.Add(item);
			}
		}
		finally
		{
			IDisposable disposable;
			if ((disposable = (enumerator as IDisposable)) != null)
			{
				disposable.Dispose();
			}
		}
		m_Step = SnappingStep.None;
	}

	private void CalcuImageDeeps(Vector2 values)
	{
		int i = 0;
		for (int count = m_ElementList.Count; i < count; i++)
		{
			for (int j = 0; j < i; j++)
			{
				Vector3 position = m_ElementList[i].position;
				float num = Mathf.Abs(position.x);
				Vector3 position2 = m_ElementList[j].position;
				if (num > Mathf.Abs(position2.x))
				{
					RectTransform value = m_ElementList[i];
					m_ElementList[i] = m_ElementList[j];
					m_ElementList[j] = value;
				}
			}
		}
		int k = 0;
		for (int count2 = m_ElementList.Count; k < count2; k++)
		{
			m_ElementList[k].SetSiblingIndex(k);
		}
	}

	private void OnEnable()
	{
		if (onSnapElementObjectEnable != null)
		{
			onSnapElementObjectEnable();
		}
		Snap2Element(0);
	}

	private void Update()
	{
		if (UnityEngine.Input.GetKeyDown(KeyCode.A))
		{
			Snap2Element(0);
		}
		if (m_Step != SnappingStep.Drag && m_Step != 0)
		{
			if (m_Step == SnappingStep.PrepareToSnapping)
			{
				FuncPrepareToSnapping();
			}
			if (m_Step == SnappingStep.Snapping)
			{
				FuncSnapping();
			}
		}
	}

	private void FuncSnapping()
	{
		float value = m_Time / m_SnapTime;
		value = Mathf.Clamp01(value);
		m_Time += Time.deltaTime;
		float x = EaseOutCubic(m_FromHorizontalPosition, m_ToHorizontalPosition, value);
		Vector3 v = m_RectContentTrans.anchoredPosition;
		v.x = x;
		m_RectContentTrans.anchoredPosition = v;
		if (value >= 1f)
		{
			if (onSnapElementComplete != null)
			{
				onSnapElementComplete(m_FocusedElement);
			}
			m_ScrollRect.velocity = Vector2.zero;
			m_Step = SnappingStep.None;
		}
	}

	public void Snap2Element(int index)
	{
		if (m_ElementList != null && base.gameObject.activeSelf && index >= 0 && index <= m_ElementList.Count - 1)
		{
			StartCoroutine(_Snap2Element(index));
		}
	}

	private IEnumerator _Snap2Element(int index)
	{
		yield return new WaitForEndOfFrame();
		Vector2 anchoredPosition = m_RectContentTrans.anchoredPosition;
		m_FromHorizontalPosition = anchoredPosition.x;
		float fromHorizontalPosition = m_FromHorizontalPosition;
		Vector3 vector = ConvertPointToScrollRectLocal(m_ElementList[index].anchoredPosition);
		m_ToHorizontalPosition = fromHorizontalPosition - vector.x;
		m_FocusedElement = m_ElementList[index];
		m_Step = SnappingStep.Snapping;
		m_ScrollRect.velocity = Vector2.zero;
		m_Time = 0f;
		currentIndex = index;
		if ((bool)m_LevelIndexUI)
		{
			m_LevelIndexUI.SetLightOn(index);
		}
	}

	private void FuncPrepareToSnapping()
	{
		Vector2 velocity = m_ScrollRect.velocity;
		if (Mathf.Abs(velocity.x) <= m_SpeedThreshold)
		{
			currentIndex = GetNearestIndex(0f);
			Snap2Element(currentIndex);
		}
	}

	private int GetNearestIndex(float value)
	{
		int result = 0;
		float num = float.MaxValue;
		int i = 0;
		for (int count = m_ElementList.Count; i < count; i++)
		{
			Vector3 vector = ConvertPointToScrollRectLocal(m_ElementList[i].anchoredPosition);
			float num2 = value - vector.x;
			if (Mathf.Abs(num2) <= num)
			{
				num = num2;
				result = i;
				continue;
			}
			break;
		}
		return result;
	}

	private float GetNearestX(float value)
	{
		float num = float.MaxValue;
		int i = 0;
		for (int count = m_ElementList.Count; i < count; i++)
		{
			Vector3 vector = ConvertPointToScrollRectLocal(m_ElementList[i].anchoredPosition);
			float num2 = value - vector.x;
			if (Mathf.Abs(num2) <= num)
			{
				num = num2;
				m_FocusedElement = m_ElementList[i];
				continue;
			}
			break;
		}
		return num;
	}

	private Vector3 ConvertPointToScrollRectLocal(Vector3 point)
	{
		return (m_ScrollRect.transform.worldToLocalMatrix * m_RectContentTrans.localToWorldMatrix).MultiplyPoint(point);
	}

	private float EaseOutCubic(float start, float end, float value)
	{
		value -= 1f;
		end -= start;
		return end * (value * value * value + 1f) + start;
	}

	public void OnBeginDrag(PointerEventData eventData)
	{
		m_Step = SnappingStep.Drag;
	}

	public void OnEndDrag(PointerEventData eventData)
	{
		if (m_Step == SnappingStep.Drag || m_Step == SnappingStep.None)
		{
			m_Step = SnappingStep.PrepareToSnapping;
		}
	}
}
